package com.company.pangu.aliyun.live.util;

import cn.hutool.crypto.SecureUtil;
import com.company.pangu.aliyun.live.config.LiveConfig;
import com.company.pangu.aliyun.live.constants.LiveConstants;
import com.company.pangu.aliyun.live.enums.ProtocolType;
import com.company.pangu.aliyun.live.enums.PullProtocolType;
import com.company.pangu.aliyun.live.enums.PushProtocolType;
import com.company.pangu.aliyun.live.enums.StreamBitRateType;
import com.company.pangu.aliyun.live.generator.AuthKeyGenerator;
import com.company.pangu.aliyun.live.generator.PullUrlGenerator;
import com.company.pangu.aliyun.live.generator.PushUrlGenerator;
import com.company.pangu.aliyun.live.response.BuildLiveChannelResponse;
import com.company.pangu.aliyun.live.strategy.UriBuildContext;

import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>live stream utils</p>
 *
 * @author youyoukele
 * @version 1.0
 * @date 2021/10/28
 */
public class LiveStreamUtils {

    /**
     * 生成推流地址
     *
     * @param liveConfig
     * @param streamName
     * @return
     */
    public static String buildPushUrl(LiveConfig liveConfig, String streamName) {
        long expireTime = liveConfig.getExpireTime();
        String pushDomain = liveConfig.getPushDomain();
        String pushKey = liveConfig.getPushKey();
        String appName = liveConfig.getAppName();
        long timestamp = System.currentTimeMillis() / 1000L + expireTime;

        String authKey = genAuthKey(appName, streamName, timestamp, PushProtocolType.RTMP, pushKey);

        // 生成push url
        PushUrlGenerator pushUrlGenerator = PushUrlGenerator.builder()
                .pushProtocolType(PushProtocolType.RTMP)
                .pushDomain(pushDomain)
                .appName(appName)
                .streamName(streamName)
                .authKey(authKey)
                .build();

        return pushUrlGenerator.gen();
    }

    /**
     * 生成播放地址
     *
     * @param liveConfig
     * @param streamName
     * @param streamTypes
     * @return
     */
    public static List<BuildLiveChannelResponse.PullUrl> buildPullUrl(LiveConfig liveConfig, String streamName, List<StreamBitRateType> streamTypes) {
        long expireTime = liveConfig.getExpireTime();
        String pullDomain = liveConfig.getPullDomain();
        String pullKey = liveConfig.getPullKey();
        String appName = liveConfig.getAppName();
        long timestamp = System.currentTimeMillis() / 1000L + expireTime;
        // 拉流集合
        return Arrays.stream(PullProtocolType.values()).map(pullProtocolType -> {
            String authKey = genAuthKey(appName, streamName, timestamp, pullProtocolType, pullKey);

            // 构建pull url
            List<BuildLiveChannelResponse.PullUrl.Stream> Streams = streamTypes.stream()
                    .map(it -> {
                        PullUrlGenerator pullUrlGenerator = PullUrlGenerator.builder()
                                .appName(appName)
                                .pullDomain(pullDomain)
                                .pullProtocolType(pullProtocolType)
                                .streamName(streamName)
                                .streamBitRateType(it)
                                .authKey(authKey)
                                .build();
                        String url = pullUrlGenerator.gen();

                        BuildLiveChannelResponse.PullUrl.Stream stream = new BuildLiveChannelResponse.PullUrl.Stream();
                        stream.setUrl(url);
                        stream.setStreamType(it);
                        return stream;
                    }).collect(Collectors.toList());

            BuildLiveChannelResponse.PullUrl pullUrl = new BuildLiveChannelResponse.PullUrl();
            pullUrl.setProtocol(pullProtocolType);
            pullUrl.setStreams(Streams);
            return pullUrl;
        }).collect(Collectors.toList());
    }

    /**
     * 生成鉴权key
     * https://help.aliyun.com/document_detail/199349.htm?spm=a2c4g.11186623.0.0.33fe2e05iaiZfz#section-ak5-3ig-mv4
     *
     * @param appName      应用名称
     * @param streamName   流名称
     * @param timestamp    有效时间戳
     * @param protocolType 协议
     * @param privateKey   key
     * @return
     */
    private static String genAuthKey(String appName, String streamName, long timestamp, ProtocolType protocolType, String privateKey) {
        // 确定uri
        String uri = UriBuildContext.builder(appName, streamName, protocolType);

        // 生成hash
        String md5hash = md5sum(uri, timestamp, LiveConstants.DEFAULT_RAND, LiveConstants.DEFAULT_UID, privateKey);

        // 生成auth key
        AuthKeyGenerator authKeyGenerator = AuthKeyGenerator.builder()
                .md5hash(md5hash)
                .uid(LiveConstants.DEFAULT_UID)
                .rand(LiveConstants.DEFAULT_RAND)
                .timestamp(timestamp)
                .build();
        return authKeyGenerator.gen();
    }


    /**
     * 通过md5算法计算出的验证串。数字和小写英文字母混合0~9、a~z，固定长度32。
     * sstring = "URI-timestamp-rand-uid-PrivateKey"
     * md5hash = md5sum(sstring)
     * <p>
     * URI：用户请求对象相对地址，即原始URL中的/AppName/StreamName，其中StreamName包含扩展名。
     * 生成FLV播放地址时，URI为/AppName/StreamName.flv。
     * 生成HLS播放地址时，URI为/AppName/StreamName.m3u8。
     * 生成FLV转码播放地址时，URI为/AppName/StreamName_ID.flv。
     * 生成HLS转码播放地址时，URI为/AppName/StreamName_ID.m3u8。
     * <p>
     * PrivateKey：控制台配置的主KEY或副KEY，二者皆可。
     * md5sum：表示计算MD5值，请使用开发语言对应的函数。
     *
     * @param uri
     * @param timestamp
     * @param rand
     * @param uid
     * @param privateKey
     * @return
     */
    private static String md5sum(String uri, long timestamp, String rand, String uid, String privateKey) {
        String stringToMd5 = MessageFormat.format(LiveConstants.MD5_STRING_FORMATTER, uri, String.valueOf(timestamp), rand, uid, privateKey);
        return SecureUtil.md5(stringToMd5);
    }

}
